/**
 * 
 */
package com.wubo.sec.acl.core;

import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * ACL管理器
 * <p>默认只有ACL_ADD、ACL_DEL、ACL_PUT、ACL_GET等四个动作，从调用addAction(String action)方法添加动作</p>
 * @author WuBo
 * @CreateDate 2012-2-24
 */
public class AclManager {
	private static AclManager instance = new AclManager();
	
	private Map<String, Integer> aclMap = new HashMap<String, Integer>();
	private Map<Integer, String> actionMap = new HashMap<Integer, String>();
	
	private AclManager(){
		aclMap.put("ACL_GET", 0x1);
		aclMap.put("ACL_ADD", 0x2);
		aclMap.put("ACL_DEL", 0x4);
		aclMap.put("ACL_PUT", 0x8);
		
		Set<String> set = aclMap.keySet();
		for(String key : set){
			actionMap.put(aclMap.get(key), key);
		}
	}
	
	public static AclManager getInstance(){
		return instance;
	}
	/**
	 * 添加ACL动作
	 * @param action
	 */
	public void addAction(String action){
		if(aclMap.containsKey(action)){
			return;
		}
		int acl = (int)Math.pow(2, aclMap.size());
		aclMap.put(action, acl);
		actionMap.put(acl, action);
	}
	/**
	 * 合并多个ACL
	 * @param acl
	 * @param addedAcls
	 * @return
	 */
	public Integer unionAcl(Integer... acls){
		Integer result = 0x0;
		for(Integer acl : acls){
			result = result | acl;
		}
		return result;
	}
	/**
	 * 根据动作得到ACL并加入到已有的ACL中
	 * @param acl
	 * @param actions
	 * @return
	 */
	public Integer appendAcl(Integer acl, String... actions){
		Integer result = acl;
		for(String action : actions){
			result = result | doGetAcl(action);
		}
		return result;
	}
	/**
	 * 从ACL中移除指定的动作
	 * @param acl
	 * @param actions
	 * @return
	 */
	public Integer removeAcl(Integer acl, String... actions){
		Integer removeAcl = getAcl(actions);
		if(removeAcl == 0x0  || acl == 0x0){
			return acl;
		}
		if(acl >= removeAcl){
			return acl ^ removeAcl;
		}
		String binString = Integer.toBinaryString(removeAcl);
		int rlen = binString.length();
		int len = Integer.toBinaryString(acl).length();
		int subAcl = Integer.parseInt(binString.substring(rlen - len), 2);
		return acl ^ subAcl;
	}
	/**
	 * 根据动作得到ACL
	 * @param actions
	 * @return
	 */
	public Integer getAcl(String... actions){
		int result = 0x0;
		for(String action : actions){
			result = result | doGetAcl(action);
		}
		return result;
	}
	
	private Integer doGetAcl(String action){
		Integer acl = aclMap.get(action);
		if(acl != null){
			return acl;
		}
		return new Integer(0);
	}
	/**
	 * 得到当前所有默认动作的ACL
	 * @return
	 */
	public Integer getAllAcl(){
		return this.getAcl(aclMap.keySet().toArray(new String[aclMap.size()]));
	}
	
	/**
	 * 判断给定的ACL是否含有指定的动作
	 * @param acl
	 * @param actions
	 * @return
	 */
	public boolean hasActions(Integer acl, String... actions){
		if(acl < 0){
			throw new IllegalArgumentException("acl must great equals 0");
		}
		if(acl == 0){
			return false;
		}
		int pointedAcl = getAcl(actions);
		return (acl & pointedAcl) > 0;
	}
	/**
	 * 得到此ACL表示的动作列表
	 * @param acl
	 * @return
	 */
	public String[] getAction(Integer acl){
		if(acl < 0){
			throw new IllegalArgumentException("acl must great equals 0");
		}
		if(acl == 0){
			return new String[]{};
		}
		List<String> result = new LinkedList<String>();
		String binary = Integer.toBinaryString(acl);
		int l = binary.length();
		for(int i=l-1,j=0; i>=0; i--,j++){
			char c = binary.charAt(i);
			if(c == '1'){
				int a = (int)Math.pow(2, j);
				result.add(actionMap.get(a));
			}
		}
		return result.toArray(new String[result.size()]);
	}
	
}
